<?php

use Core\HttpServer;
use Core\Log;
use Core\Config;

class Index
{

	public static $config = [];
	public static $class_obj = [];

	/**
	 * init
	 */
	private static function _init()
	{
		error_reporting(E_ALL);
		define('APP_PATH', __DIR__);
		define('RUNTIME_PATH', __DIR__ . '/Runtime');

		if (is_file(APP_PATH . '/App/Common/functions.php'))
			include APP_PATH . '/App/Common/functions.php';

		//自动加载
		spl_autoload_register(function($name) {
			$class_path = __DIR__ . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $name) . '.class.php';
			if (!is_file($class_path))
				die('文件' . $class_path . '未找到');
			if (!isset(self::$class_obj[$class_path]))
				include $class_path;
		});

		//运行环境检查
		\Core\CheckEnv::check();
	}

	public static function run()
	{
		//初始化
		self::_init();

		//命令解析
		self::_parseCommand();
	}

	/**
	 * 解析启动命令,比如start, stop等 执行不同的操作
	 */
	private static function _parseCommand()
	{
		global $argv;

		$startFilename = $argv[0];
		if (!isset($argv[1]) || $argv[1] == '')
			die("Usage: php " . $startFilename . " start|stop|restart|status \n");

		$operation = strtolower(trim($argv[1]));
		//获取主进程ID - 用来判断当前进程是否在运行
		$masterPid = false;
		$pid_file = Config::getInstance()->get('common.master_pid_file');
		if (file_exists($pid_file))
			$masterPid = file_get_contents($pid_file);

		//主进程当前是否正在运行
		$masterIsAlive = false;
		//给Service主进程发送一个信号, 信号为SIG_DFL, 表示采用默认信号处理程序.如果发送信号成功则该进程正常
		if ($masterPid && self::checkMasterIsAlive())
			$masterIsAlive = true;

		//启动不能重复启动
		if ($masterIsAlive && $operation === 'start')
			Log::write('Service is already running. file: ' . $startFilename, 'FATAL');

		//未启动不能终止
		if (!$masterIsAlive && $operation === 'stop')
			Log::write('Service is not running.', 'FATAL');

		//根据不同的执行参数执行不同的动作
		switch ($operation) {
			//启动
			case 'start':
				self::_commandStart();
				break;
			//停止
			case 'stop':
				self::_commandStop();
				break;
			//重启
			case 'restart':
				self::_commandRestart();
				break;
			//状态
			case 'status':
				self::_commandStatus($masterPid);
				break;
			//参数不合法
			default:
				Log::write('Parameter error. Usage: php ' . $startFilename . ' start|stop|restart|status', 'FATAL');
				echo "Usage: php " . $startFilename . " start|stop|restart|status \n";
		}
	}

	/**
	 * 启动
	 */
	private static function _commandStart()
	{
		Log::write('Service start');

		if (self::checkMasterIsAlive()) {
			echo "Service is runing \n";
			return false;
		}

		self::_daemon();

		//启动HttpServer
		self::_startHttp();
	}

	/**
	 * 停止
	 * @param type $masterPid
	 */
	private static function _commandStop()
	{
		Log::write('Service stop');

		if (self::checkMasterIsAlive() == false) {
			echo "Service is not runing \n";
			exit(0);
		}

		$grep_name = Config::getInstance()->get('common.master_process_name');
		exec("ps aux | grep $grep_name | grep -v grep | awk '{print $2}' |xargs kill -SIGINT");
		exit(0);
	}

	/**
	 * 重启
	 * @param type $masterPid
	 * @param type $isDomain
	 */
	private static function _commandRestart()
	{
		Log::write('Service restart');

		if (self::checkMasterIsAlive() == false) {
			self::_daemon();
			//启动HttpServer
			self::_startHttp();
			return true;
		}

		$grep_name = Config::getInstance()->get('common.master_process_name');
		exec("ps aux | grep $grep_name | grep -v grep | awk '{print $2}' |xargs kill -SIGINT");
		self::_daemon();
		//启动HttpServer
		self::_startHttp();

		return true;
	}

	/**
	 * 状态
	 * @param type $masterPid
	 */
	private static function _commandStatus($masterPid)
	{
		$isAlive = self::checkMasterIsAlive();

		if (!$isAlive)
			echo "service is not running.\n";
		else
			echo "service is running. Pid:$masterPid\n";
	}

	/**
	 * 已守护进程的方式启动
	 */
	private static function _daemon()
	{
		//文件掩码清0
		umask(0);
		//创建一个子进程
		$pid = pcntl_fork();
		//fork失败
		if ($pid === -1) {
			Log::write('_daemon: fork failed', 'FATAL');
			//父进程
		} else if ($pid > 0) {
			exit();
		}
		//设置子进程为Session leader, 可以脱离终端工作.这是实现daemon的基础
		if (posix_setsid() === -1) {
			Log::write('_daemon: set sid failed', 'FATAL');
		}
		//再次在开启一个子进程
		//这不是必须的,但通常都这么做,防止获得控制终端.
		$pid2 = pcntl_fork();
		if ($pid2 === -1) {
			Log::write('_daemon: fork2 failed', 'FATAL');
			//将父进程退出
		} else if ($pid2 > 0) {
			exit();
		}
	}

	/**
	 * 启动HTTP服务
	 */
	private static function _startHttp()
	{
		//设置进程名称
		self::setProcessTitle();

		//启动服务
		$config = Config::getInstance()->get('http');
		HttpServer::run('tcp://' . $config['lesten_ip'] . ':' . $config['lesten_port']);
	}

	/**
	 * 检查是否在运行
	 * @return boolean
	 */
	private static function checkMasterIsAlive()
	{
		$pid_file = Config::getInstance()->get('common.master_pid_file');
		$grep_name = Config::getInstance()->get('common.master_process_name');
		$output = '';
		exec("ps -ef | grep $grep_name | grep -v grep", $output);
		if (empty($output)) {
			if (file_exists($pid_file))
				unlink($pid_file);
			return false;
		} else {
			return true;
		}
	}

	/**
	 * 设置进程名称
	 * @param type $title
	 */
	private static function setProcessTitle()
	{
		$title = Config::getInstance()->get('common.master_process_name');
		if (function_exists('cli_set_process_title')) {
			cli_set_process_title($title);
		} elseif (extension_loaded('proctitle') && function_exists('setproctitle')) {
			setproctitle($title);
		}
	}

}

Index::run();
